package com.kou.backend.service.impl.file;

import cn.hutool.core.util.ObjectUtil;
import com.kou.backend.entity.FileResourceDO;
import com.kou.backend.enums.FileOpsTypeEnum;
import com.kou.backend.error.CommonErrorEnum;
import com.kou.backend.exception.CommonException;
import com.kou.backend.request.file.UploadFileRequestDTO;
import com.kou.backend.util.FileUtils;
import io.minio.*;
import io.minio.http.Method;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

/**
 * @author: kou
 * @since: 2025/6/26 17:35
 */
@Slf4j
@Service("minioFileStorageService")
public class MinioFileStorageServiceImpl extends AbstractFileStorageService {

    @Override
    public void saveFile(MultipartFile file, UploadFileRequestDTO requestDTO, String relativePath, String uploader) {
        try (InputStream is = file.getInputStream()) {
            minioClient.putObject(
                    PutObjectArgs.builder()
                            .bucket(bucket)
                            .object(relativePath)
                            .stream(is, file.getSize(), -1)
                            .contentType(file.getContentType())
                            .build()
            );
        } catch (Exception e) {
            log.error("MinIO 上传失败", e);
            throw new CommonException(CommonErrorEnum.ERROR_UPLOAD_FILE);
        }
    }

    @Override
    public InputStream getFileStream(String fileId) throws IOException {
        try {
            FileResourceDO fileResourceDO = fileResourceDao.selectById(fileId);
            if (ObjectUtil.isEmpty(fileResourceDO)) {
                throw new CommonException(CommonErrorEnum.ERROR_FILE_NOT_EXIST);
            }
            return minioClient.getObject(
                    GetObjectArgs.builder().bucket(bucket).object(fileResourceDO.getStoragePath()).build()
            );
        } catch (Exception e) {
            log.error("MinIO 读取失败", e);
            throw new IOException("MinIO 读取失败", e);
        }
    }

    @Override
    public void fileStreamToResponse(String fileId, String type, HttpServletResponse response) throws IOException {
        try {
            FileResourceDO fileResourceDO = fileResourceDao.selectById(fileId);
            if (ObjectUtil.isEmpty(fileResourceDO)) {
                throw new CommonException(CommonErrorEnum.ERROR_FILE_NOT_EXIST);
            }
            GetObjectResponse fileStream = minioClient.getObject(
                    GetObjectArgs.builder().bucket(bucket).object(fileResourceDO.getStoragePath()).build()
            );
            if (FileOpsTypeEnum.PREVIEW.getFileOpsType().equals(type)) {
                //预览header
                FileUtils.previewToResponse(fileStream, fileResourceDO.getStoragePath(), response);
            } else if (FileOpsTypeEnum.DOWNLOAD_FILE.getFileOpsType().equals(type)) {
                FileUtils.downloadToResponse(fileStream, fileResourceDO.getStoragePath(), response);
            }
        } catch (Exception e) {
            log.error("MinIO 读取失败", e);
            throw new IOException("MinIO 读取失败", e);
        }
    }

    /**
     * mini io 生成预签名URL
     *
     * @param fileId
     * @param expireSeconds
     * @return
     */
    public String generatePresignedUrl(String fileId, Integer expireSeconds) {
        try {
            FileResourceDO fileResourceDO = fileResourceDao.selectById(fileId);
            if (ObjectUtil.isEmpty(fileResourceDO)) {
                throw new CommonException(CommonErrorEnum.ERROR_FILE_NOT_EXIST);
            }
            return minioClient.getPresignedObjectUrl(
                    GetPresignedObjectUrlArgs.builder()
                            .method(Method.GET)
                            .bucket(bucket)
                            .object(fileResourceDO.getStoragePath())
                            .expiry(expireSeconds)
                            .build()
            );
        } catch (Exception e) {
            throw new RuntimeException("生成预签名URL失败", e);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteFile(String userAccount, String uploader) throws IOException {
        deleteUserFileDb(uploader, userAccount);
        try {
            minioClient.removeObject(
                    RemoveObjectArgs.builder().bucket(bucket).object(userAccount).build()
            );
        } catch (Exception e) {
            log.error("MinIO 删除失败", e);
            throw new IOException("MinIO 删除失败", e);
        }
    }

    @Override
    public boolean checkFileExists(String fileMd5) {
        return false;
    }

    @Override
    public List<Integer> getUploadedChunks(String fileMd5) {
        return List.of();
    }

    @Override
    public void uploadChunk(String fileMd5, Integer chunkNumber, MultipartFile chunkFile, String uploader) throws IOException {

    }

    @Override
    public String mergeChunks(String fileMd5, String uploader, String originalFileName) throws IOException {
        return "";
    }

    @Override
    public FileResourceDO getFileResourceDO(String fileId) {
        return fileResourceDao.selectById(fileId);
    }
}
